package com.example.springboot.service.impl;;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot.entity.Collect;
import com.example.springboot.entity.Item;
import com.example.springboot.entity.User;
import com.example.springboot.mapper.CollectMapper;
import com.example.springboot.mapper.ItemMapper;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.service.IItemService;
import com.example.springboot.service.impl.recommend.RelateDTO;
import com.example.springboot.service.impl.recommend.UserCF;
import com.example.springboot.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService{

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ItemMapper itemMapper;

    @Autowired
    private CollectMapper collectMapper;

    @Override
    public boolean save(Item entity) {
        return super.save(entity);
    }

    @Override
    public boolean updateById(Item entity) {
        return super.updateById(entity);
    }

    @Override
    public boolean removeById(Item entity) {
        return super.removeById(entity);
    }

    @Override
    public boolean removeBatchByIds(Collection<?> list) {
        return super.removeBatchByIds(list);
    }

    @Override
    public List<Item> list() {
        return super.list();
    }

    @Override
    public Item getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    public <E extends IPage<Item>> E page(E page, Wrapper<Item> queryWrapper) {
        return super.page(page, queryWrapper);
    }
    
    @Override
    public List<Item> recommend() {
        User currentUser = TokenUtils.getCurrentUser();
        if (ObjectUtil.isEmpty(currentUser)) {
            // 没有用户登录
            return new ArrayList<>(getRandomGoods(10));
        }
        // 用户的哪些行为可以认为他跟人物产生了关系？收藏
        // 1. 获取所有的收藏信息
        List<Collect> allCollects = collectMapper.selectList(null);

        // 5. 获取所有的用户信息
        List<User> allUsers = userMapper.selectList(null);
        // 6. 获取所有的人物信息
        List<Item> all = itemMapper.selectList(null);

        // 定义一个存储每个人物和每个用户关系的List
        List<RelateDTO> data = new ArrayList<>();
        // 定义一个存储最后返回给前端的人物List
        List<Item> result = new ArrayList<>();

        // 开始计算每个人物和每个用户之间的关系数据
        for (Item goods : all) {
            Integer goodsId = goods.getId();
            for (User user : allUsers) {
                Integer userId = user.getId();
                int index = 1;
                // 1. 判断该用户有没有收藏该人物，收藏的权重我们给 1
                Optional<Collect> collectOptional = allCollects.stream().filter(x -> x.getItemId().equals(goodsId) && x.getUserId().equals(userId)).findFirst();
                if (collectOptional.isPresent()) {
                    index += 2;
                }
                if (index > 1) {
                    RelateDTO relateDTO = new RelateDTO(userId, goodsId, index);
                    data.add(relateDTO);
                }
            }
        }

        // 数据准备结束后，就把这些数据一起喂给这个推荐算法
        List<Integer> goodsIds = UserCF.recommend(currentUser.getId(), data);
        // 把人物id转换成人物
        List<Item> recommendResult = goodsIds.stream().map(goodsId -> all.stream()
                        .filter(x -> x.getId().equals(goodsId)).findFirst().orElse(null))
                .limit(10).collect(Collectors.toList());

        if (CollectionUtil.isEmpty(recommendResult)) {
            // 随机给它推荐10个
            return getRandomGoods(10);
        }
        if (recommendResult.size() < 10) {
            int num = 10 - recommendResult.size();
            List<Item> list = getRandomGoods(num);
            result.addAll(list);
        }
        return recommendResult;
    }

    private List<Item> getRandomGoods(int num) {
        List<Item> list = new ArrayList<>(num);
        List<Item> goods = itemMapper.selectList(null);
        for (int i = 0; i < num; i++) {
            int index = new Random().nextInt(goods.size());
            list.add(goods.get(index));
        }
        return list;
    }

}
